package com.luna.hbase.mapper;

import cn.hutool.core.convert.Convert;
import com.luna.hbase.annotation.HbaseColumn;
import com.luna.hbase.api.Mapper;
import com.luna.hbase.exception.HbaseException;
import com.luna.hbase.utils.HBaseUtil;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.client.Result;
import org.springframework.core.ResolvableType;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.List;

/**
 * @author Allen Wong
 * @version V1.0.0
 * Hbase结果映射实现类
 * 2022/3/31 21:44
 */
public class RowMapper<T> implements Mapper<T> {

    @Override
    @SuppressWarnings("unchecked")
    public T mapping(Result result) throws Exception {
        Assert.notNull(result, "Result could not be null!");

        Class<?> clazz = ResolvableType.forClass(this.getClass()).getSuperType().getGeneric(0).resolve();
        Assert.notNull(clazz, "Class could not be null!");

        T entity = (T) clazz.newInstance();
        List<Cell> cells = result.listCells();
        for (Cell cell : cells) {
            String columnQualifier = HBaseUtil.column(cell);
            String value = HBaseUtil.value(cell);
            Field[] fields = clazz.getDeclaredFields();

            for (Field field : fields) {
                // Class<?> type = field.getType();
                // if (String.class != type) {
                //     throw new HbaseException("The field present with @HbaseColumn must be String type!");
                // }

                ReflectionUtils.makeAccessible(field);
                if (field.getName().equalsIgnoreCase(columnQualifier)) {
                    convert(field, entity, value);
                } else if (field.isAnnotationPresent(HbaseColumn.class)) {
                    String hbaseColumn = field.getAnnotation(HbaseColumn.class).value();
                    if (columnQualifier.equals(hbaseColumn)) {
                        convert(field, entity, value);
                    }
                }

            }
        }
        return entity;
    }

    private void convert(Field field, T entity, String value) {
        Class<?> type = field.getType();
        if (String.class == type) {
            ReflectionUtils.setField(field, entity, value);
        } else if (Character.class == type || char.class == type) {
            ReflectionUtils.setField(field, entity, Convert.toChar(value));
        } else if (Byte.class == type || byte.class == type) {
            ReflectionUtils.setField(field, entity, Convert.toByte(value));
        } else if (Short.class == type || short.class == type) {
            ReflectionUtils.setField(field, entity, Convert.toShort(value));
        } else if (Integer.class == type || int.class == type) {
            ReflectionUtils.setField(field, entity, Convert.toInt(value));
        } else if (Long.class == type || long.class == type) {
            ReflectionUtils.setField(field, entity, Convert.toLong(value));
        } else if (Float.class == type || float.class == type) {
            ReflectionUtils.setField(field, entity, Convert.toFloat(value));
        } else if (Double.class == type || double.class == type) {
            ReflectionUtils.setField(field, entity, Convert.toDouble(value));
        } else if (Boolean.class == type || boolean.class == type) {
            ReflectionUtils.setField(field, entity, Convert.toBool(value));
        } else if (BigDecimal.class == type) {
            ReflectionUtils.setField(field, entity, Convert.toBigDecimal(value));
        } else {
            throw new HbaseException("The field type not support!");
        }
    }
}
